package edu.unice.simul.modele.initialisation;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.swing.event.EventListenerList;

import edu.unice.simul.events.BlockChangedEvent;
import edu.unice.simul.listeners.PieceListener;
import edu.unice.simul.util.Dim;
import edu.unice.simul.vue.initialisation.modes_dessin.BlockType;

/**
 * Cette classe représente le modèle de l'initialisation de la pièce (dessin).
 * 
 * @author Romain Ciaccafava
 * 
 */
public class Initialisation {
	private BlockType[][] world;
	private Dim dim;
	private EventListenerList listeners = new EventListenerList();

	public Initialisation(Dim dim) {
		this.dim = dim;
		world = new BlockType[dim.getX()][dim.getY()];
		clearWorld();
	}

	/**
	 * Modifie la nature d'un block à une coordonnée
	 * 
	 * @param pos
	 *          coordonéees du block
	 * @param blockType
	 *          type du nouveau block
	 */
	public void modifierBlock(Dim pos, BlockType blockType) {
		if (pos.getX() < dim.getX() && pos.getY() < dim.getY() && pos.getX() >= 0
				&& pos.getY() >= 0) {
			world[pos.getX()][pos.getY()] = blockType;
			firePieceListeners(pos, blockType);
		}
	}

	/**
	 * Met à jour la nature d'un block à une coordonnée dans les vues
	 */
	public void firePieceListeners(Dim pos, BlockType blockType) {
		PieceListener[] listenerList = (PieceListener[]) listeners
				.getListeners(PieceListener.class);

		for (PieceListener listener : listenerList) {
			listener.pieceChanged(new BlockChangedEvent(this, pos, blockType));
		}
	}

	/**
	 * Avertit les vues de la remise à zéro de la pièce
	 */
	public void firePieceCleared() {
		PieceListener[] listenerList = (PieceListener[]) listeners
				.getListeners(PieceListener.class);

		for (PieceListener listener : listenerList) {
			listener.pieceCleared();
		}
	}

	public BlockType[][] getWorld() {
		return this.world;
	}

	/**
	 * Remise à zéro de la pièce
	 */
	public void clearWorld() {
		for (int i = 0; i < dim.getX(); i++)
			for (int j = 0; j < dim.getY(); j++)
				world[i][j] = BlockType.NOTHING;

		firePieceCleared();
	}

	/**
	 * Inscrit un écouteur de pièce au modèle
	 */
	public void addPieceListener(PieceListener listener) {
		listeners.add(PieceListener.class, listener);
	}

	/**
	 * Désinscrit un écouteur de pièce au modèle
	 */
	public void removePieceListener(PieceListener listener) {
		listeners.remove(PieceListener.class, listener);
	}

	/**
	 * Enregistre la pièce dans un fichier
	 */
	public void save(File file) throws FileNotFoundException, IOException {
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
		out.writeObject(world);
		out.flush();
		out.close();
	}

	/**
	 * Charge la pièce depuis un fichier
	 */
	public void load(File file) throws FileNotFoundException, IOException,
			ClassNotFoundException {
		ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
		BlockType[][] w = (BlockType[][]) in.readObject();
		this.world = w;
		in.close();
		fireAll();
	}

	/**
	 * Met à jour la totalité de la pièce dans les vues
	 */
	private void fireAll() {
		PieceListener[] listenerList = (PieceListener[]) listeners
				.getListeners(PieceListener.class);

		for (PieceListener listener : listenerList) {
			for (int i = 0; i < world.length; i++)
				for (int j = 0; j < world[i].length; j++) {
					listener.pieceChanged(new BlockChangedEvent(this, new Dim(j, i),
							world[j][i]));
				}
		}
	}

	/**
	 * Vérifie que la pièce est vide
	 */
	public boolean vide() {
		for (int i = 0; i < world.length; i++)
			for (int j = 0; j < world[i].length; j++)
				if (world[i][j] == BlockType.HUMAIN)
					return false;

		return true;
	}
}
